package com.attrisoft.sanger.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jfileupload.jspupload.FileUploadBean;
import jfileupload.jspupload.MultipartFormDataRequest;
import jfileupload.jspupload.UploadFile;

import com.attrisoft.sanger.aws.FileInfo;
import com.attrisoft.sanger.aws.S3Client;
 
public class UploadServlet extends HttpServlet {
    
    private static final long serialVersionUID = -6515017838213245351L;

    static String directory = "uploads";
    static String tmpdirectory = "uploads/tmp";
    static boolean createsubfolders = true;
    static boolean allowresume = true;
    static boolean allowoverwrite = true;
    static String encoding = "ISO-8859-1";
    static boolean keepalive = false;

    private FileUploadBean upBean = new FileUploadBean();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String file = request.getParameter("file");
        String workflow = request.getParameter("workflow");
        String get = request.getParameter("get");
        if (workflow != null) {
            String xml = "<workflow>";
            for (FileInfo info: S3Client.getInput(request.getUserPrincipal().getName(), workflow)) {
                xml += "<input>";
                xml += "<name>" +info.getName() +"</name>";
                xml += "<size>" +info.getSize() +"</size>";
                xml += "<modified>" +info.getModified() +"</modified>";
                xml += "</input>";
            }
            for (FileInfo info: S3Client.getOutput(request.getUserPrincipal().getName(), workflow)) {
                xml += "<output>";
                xml += "<name>" +info.getName() +"</name>";
                xml += "<size>" +info.getSize() +"</size>";
                xml += "<modified>" +info.getModified() +"</modified>";
                xml += "</output>";
            }
            xml += "</workflow>";
            response.getWriter().println(xml);
            response.getWriter().flush();
        }
        else if ("previous".equals(get)) {
            String xml = "<workflows>";
            for (String flow : S3Client.getWorkflows(request.getUserPrincipal().getName())) {
                xml += "<workflow>";
                xml += "<name>" + flow +"</name>";
                xml += "</workflow>";
            }
            xml += "</workflows>";
            response.getWriter().println(xml);
            response.getWriter().flush();
        }
        else if ("current".equals(get)) {
            String xml = "<workflows>";
            for (String flow : Workflow.getCurrent(request.getUserPrincipal().getName())) {
                xml += "<workflow>";
                xml += "<name>" + flow +"</name>";
                xml += "</workflow>";
            }
            xml += "</workflows>";
            response.getWriter().println(xml);
            response.getWriter().flush();
        }
        else if (file != null) {
            String name = file.substring(file.lastIndexOf('/')+1);
            response.setHeader("Content-disposition", "attachment; filename=\"" +name+"\"");
            InputStream is = S3Client.get(request.getUserPrincipal().getName(), file);
            byte[] buf= new byte[1024];
            int read;
            while ((read = is.read(buf)) >= 0) {
                response.getOutputStream().write(buf, 0, read);
            }
            response.getOutputStream().flush();
        }
    }

    @Override
    protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        String workflow = request.getParameter("workflow");
        if (workflow != null)
            S3Client.deleteWorkflow(request.getUserPrincipal().getName(), workflow);
    }
    
    @Override
    protected void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }
    @Override
    protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }
    @Override
    protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }
    
    @Override
    protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        List<String> errors = Scheduler.schedule(
            request.getUserPrincipal().getName(), 
            directory +File.separator + request.getUserPrincipal().getName(), 
            request.getParameter("name"),
            request.getParameter("email"),
            request.getParameter("pre"),
            request.getParameter("inflation"));
        if (errors.size() > 0) {
            String xml = "<errors>";
            for (String error : errors) {
                xml += "<error>" +error +"</error>";
            }
            xml += "</errors>";
            System.err.println(" => " +xml);
            response.getWriter().println(xml);
            response.getWriter().flush();
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (!MultipartFormDataRequest.isMultipartFormData(request))
            return;
        try {
            // Parse multipart HTTP POST request.
            MultipartFormDataRequest mrequest = null;
            try {
                mrequest = new MultipartFormDataRequest(request, null, -1,
                    MultipartFormDataRequest.CFUPARSER, encoding, allowresume);
            } catch (Exception e) {
                // Cancel current upload (e.g. Stop transfer)
                // Only if allowresume = false
            }
            String account = mrequest.getParameter("account");
            if (account == null)
                throw new ServletException("Not logged in");
            else if (!account.startsWith("/"))
                account = "/" + account;
            upBean.setFolderstore(directory + account);
            Hashtable files = mrequest.getFiles();
            if ((files != null) && (!files.isEmpty())) {
                UploadFile file = (UploadFile) files.get("uploadfile");
                if (file.getFileSize() > (64 * 1024 * 1024)) {
                    response.setStatus(HttpServletResponse.SC_PAYMENT_REQUIRED);
                    return;
                }
                // Folders and subfolders creation support.
                String relative = mrequest.getParameter("relativefilename");
                if ((createsubfolders == true) && (relative != null)) {
                    String subfolder = getSubFolder(relative, file.getFileName());
                    if (subfolder != null)
                        upBean.setFolderstore(directory + account + java.io.File.separator + subfolder);
                }
                if (keepalive == false)
                    response.setHeader("Connection", "close");
                // Chunks recomposion support.
                String chunkidStr = mrequest.getParameter("chunkid");
                String chunkamountStr = mrequest.getParameter("chunkamount");
                String chunkbaseStr = mrequest.getParameter("chunkbase");
                if ((chunkidStr != null) && (chunkamountStr != null) && (chunkbaseStr != null)) {
                    // Always overwrite chunks.
                    upBean.store(mrequest, "uploadfile");
                    int chunkid = Integer.parseInt(chunkidStr);
                    int chunkamount = Integer.parseInt(chunkamountStr);
                    if (chunkid == chunkamount) {
                        // recompose file.
                        String fname = upBean.getFolderstore() + java.io.File.separator + chunkbaseStr;
                        File fread = new File(fname);
                        if (fread.canRead() && (upBean.getOverwrite() == false))
                            fname = fname + "." + System.currentTimeMillis();
                        FileOutputStream fout = new FileOutputStream(fname);
                        byte[] buffer = new byte[4096];
                        for (int c = 1; c <= chunkamount; c++) {
                            File filein = new File(upBean.getFolderstore() + java.io.File.separator + chunkbaseStr + "." + c);
                            FileInputStream fin = new FileInputStream(filein);
                            int read = -1;
                            while ((read = fin.read(buffer)) > 0)
                                fout.write(buffer, 0, read);
                            fin.close();
                            filein.delete();
                        }
                        fout.close();
                    }
                } 
                else {
                    upBean.store(mrequest, "uploadfile");
                    String type = mrequest.getParameter("type");
                    PrintWriter writer = new PrintWriter(new FileWriter(
                        upBean.getFolderstore() +File.separator + type +".name"));
                    writer.println(file.getFileName());
                    writer.flush();
                    writer.close();
                }
            } 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getSubFolder(String relative, String filename) {
        String subfolder = null;
        if ((filename != null) && (relative != null)) {
            int inda = relative.length();
            int indb = filename.length();
            if (inda > indb) {
                subfolder = relative.substring(0, (inda - indb) - 1);
                subfolder = subfolder.replace('\\', '/').replace('/', java.io.File.separatorChar);
            }
        }
        return subfolder;
    }
}